/*
 *  The scanner definition for COOL.
 */

/*
 *  Stuff enclosed in %{ %} in the first section is copied verbatim to the
 *  output, so headers and global definitions are placed here to be visible
 * to the code in the file.  Don't remove anything that was here initially
 */
%{
#include <cool-parse.h>
#include <stringtab.h>
#include <utilities.h>

/* The compiler assumes these identifiers. */
#define yylval cool_yylval
#define yylex  cool_yylex

/* Max size of string constants */
#define MAX_STR_CONST 1025
#define YY_NO_UNPUT   /* keep g++ happy */

extern FILE *fin; /* we read from this file */

/* define YY_INPUT so we read from the FILE fin:
 * This change makes it possible to use this scanner in
 * the Cool compiler.
 */
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
	if ( (result = fread( (char*)buf, sizeof(char), max_size, fin)) < 0) \
		YY_FATAL_ERROR( "read() in flex scanner failed");

char string_buf[MAX_STR_CONST]; /* to assemble string constants */
char *string_buf_ptr;

extern int curr_lineno;
extern int verbose_flag;

extern YYSTYPE cool_yylval;
int comment_counter;
int string_counter;
char * check_error(int type)
{	
	switch (type)
	{
	
	case 1:
		if(comment_counter==0)
		{
			return "OK";
		}
		break;
	case 2:
		break;
	}
	return "ERR";
}

/*
 *  Add Your own definitions here
 */

%}

/*
 * Define names for regular expressions here.
 */

DARROW          =>
INTEGER		[0-9]+
TYPEIDN		[A-Z][a-zA-Z0-9_]*
OBJIDN		[a-z][a-zA-Z0-9_]*
STRING		\"[a-zA-Z]*\"
WHITE    	[\n]
L			[a-zA-Z_]
SL             \"[a-zA-Z0-9\t\\n ]*\" 
%%
 /*
  *  Nested comments
  */


 /*
  *  The multiple-character operators.
  */
{DARROW}		{ return (DARROW); }

 /*
  * Keywords are case-insensitive except for the values true and false,
  * which must begin with a lower-case letter.
  */
[Ee][lL][sS][Ee]	{ 
	if(check_error(1)=="OK") return (ELSE);
		
	 }

[iI][Ff]		{ 
	if(check_error(1)=="OK") return (IF); }

[lL][Oo][Oo][Pp]		{ 
	 if(check_error(1)=="OK") return (LOOP); }

[Cc][Ll][aA][Ss][Ss]		{ 
			
	if(check_error(1)=="OK") return (CLASS); }

[Ff][iI]		{ 
	if(check_error(1)=="OK") return (FI); }

[Ii][Nn]		{ 
	if(check_error(1)=="OK") return (IN); }
[iI][nN][hH][eE][Rr][Ii][Tt][Ss]		{ 
	if(check_error(1)=="OK") return (INHERITS); }

[iI][Ss][Vv][Oo][Ii][Dd]		{ 
	if(check_error(1)=="OK") return (ISVOID); }

[Ll][Ee][Tt]		{ 
	if(check_error(1)=="OK") return (LET); }

[Pp][Oo][Oo][Ll]		{ 
	if(check_error(1)=="OK") return (POOL); }

[tT][Hh][Ee][Nn]		{ 
	if(check_error(1)=="OK") return (THEN); }

[wW][Hh][Ii][Ll][Ee]		{ 
	if(check_error(1)=="OK") return (WHILE); }

[Cc][Aa][Ss][Ee]		{ 
	if(check_error(1)=="OK") return (CASE); }

[Ee][Ss][Aa][Cc]		{ 
	if(check_error(1)=="OK") return (ESAC); }

[Nn][Ee][Ww]		{ 
	if(check_error(1)=="OK") return (NEW); }

[Oo][Ff]		{ 
	if(check_error(1)=="OK") return (OF); }
	
[Nn][Oo][Tt]		{ 
	if(check_error(1)=="OK") return (NOT); }
{INTEGER}		{ 
	if(check_error(1)=="OK")
	{
		cool_yylval.symbol=inttable.add_string(yytext);		 
		return (INT_CONST); }
	}
t[rR][Uu][Ee]	{
		if(check_error(1)=="OK"){cool_yylval.boolean=true;
		return BOOL_CONST;}
	}
f[Aa][Ll][sS][Ee]	{
		if(check_error(1)=="OK"){cool_yylval.boolean=false;
		return BOOL_CONST;}
	}


\" 	{ 	
		
		    register int c;
		    char * s=(char*)malloc(MAX_STR_CONST);
		    int i=0,null_error=0,eof_error=0,newline_error=0,unterm_error=0,long_error=0,escnull_error=0;	
		    int endof_string=0;
		    while (1)
			    {
				 c = yyinput(); 
				 if(c=='\\')
				  {
				      c = yyinput();//printf("");
				      if(c=='\n')
				      {
					      s[i]='\n';
					      curr_lineno++;
				      }
				      else if(c=='n')
				      {
					       s[i]='\n';
				      }
				      else if(c=='\t' || c=='t')
				      {
					    s[i]='\t';
				      }
				       else if(c=='\b' || c=='b')
				      {
					    s[i]='\b';
				      }
				      
				       else if(c=='\f' || c=='f')
				      {
					    s[i]='\f';
				      }
				      else if (c=='"')
				      {
					 
					 s[i]='"';
					// escnull_error=1;
					 //break;
				      }
				      else if (c==EOF)
				      {
					  eof_error=1;
					  break;
				      }
				      else if (c==0)
				      {
					   escnull_error=1;
					   //printf("on loophere");
					   // break;
				      }
				       else if (c=='0')
				      {
					  s[i]='0';
					  //escnull_error=1;
					  //break;
				      }
				      else if (c==32)
				      {
					  s[i]=32;
				      }
				      else
				      {
					   s[i]=c;
				      }
				}
				else if(c=='"')
				{
				      endof_string=1;
				      break;
				 }
				else if(c==EOF)
				{
				       eof_error=1;
					break;
				 }
				else if(c==0)
				{
				        escnull_error=1;
					//curr_lineno++;printf("here");
					//break;
					
				 }
				else if(c=='\n')
				{
				        newline_error=1;
					curr_lineno++;
					break;
					
				 }
				else
				 {
				    s[i]=c;

				  }
				//printf("%c-%d ",s[i],s[i]);
				i++;
				
				
 
		 }
		if(i==MAX_STR_CONST)
		{
			long_error=1;
		     
					
		}

		s[i+1]='\0';
		//printf("eof-%d end-%d,escnull-%d",eof_error,endof_string,escnull_error);
		if(null_error==1)
		{
			   cool_yylval.error_msg="String contains null character.";
			   return ERROR;
		}
		else if(escnull_error==1)
		{
			   cool_yylval.error_msg="String contains escaped null character.";
			   return ERROR;
		}
		else if((eof_error==1 || endof_string==0) )
		{
			  
			  cool_yylval.error_msg="Unterminated string constant.";
			  return ERROR;
		}
		else if(long_error==1)
		{
			   cool_yylval.error_msg="String constant is too long.";
			   return ERROR;
		}
		cool_yylval.symbol=stringtable.add_string(s);
		return STR_CONST;
		 





	}





"\n" 	{curr_lineno++;}


[\1-\7] {
	   cool_yylval.error_msg= yytext;
	  return ERROR;
  }
      
		

[\r\f\b\t\v ]* {}
'|">"|"["|"]"|"_"|"!"|"#"|"$"|"%"|"^"|"&"|"?"|"`"|"\\"|"|" { 
      if(check_error(1)=="OK")
      {
	  cool_yylval.error_msg= yytext;
	  return ERROR;
	
      }
    }

"(*"	{ 
		int comment=1,eof_error=0;
		char c;
		//printf("(*");
		while(1){
			  c=yyinput();
			 // printf("%c",c);
			   if(c=='\n') curr_lineno++;
			  if(c=='*')
			  {
			     c=yyinput();
			     //printf("%c",c);
			     if(c==')')
			     {comment--;}
			   //  
			    else if(c!=EOF) {yyunput((int)c,yytext);}
			   // if(c=='\n') curr_lineno++;
			  }
			  if(c=='(')
			  {
			     c=yyinput();
			   //  printf("%c",c);
			     if(c=='*')
			     {comment++;}
			   // if(c=='\n') curr_lineno++;
			  }
			  if(c==EOF)
			  {
			      eof_error=1;
			      break;
			   }
			  if(comment==0)
			  {
				c=yyinput();
				if(c=='\n') curr_lineno++;
				else if(c!=EOF) {yyunput((int)c,yytext);}
				break;
			  }
			 
			 
		
		}
		//printf("Line No %d",curr_lineno-1);
		if(comment<0)
		{
		    cool_yylval.error_msg="Unmatched *)";
		    curr_lineno++;
		    return ERROR;
		}
		if(eof_error==1 || comment>0)
		{
		  cool_yylval.error_msg="EOF in comment.";
		  return ERROR;
		}
		//printf("EXIT");
    }

"*)" { cool_yylval.error_msg="Unmatched *)";
		    return ERROR;}

-- {
	char c;
	int eof_error;
	while(1){
		  c=yyinput();
		  //printf("%c-%d",c,c);
		  if(c==EOF)
		  {
			
			break;
		   }
		  if(c=='\n')
		   {
			curr_lineno++;
			break;
		    }
	}
	

    }

"<=" { return LE; }

";"|","|"*"|"="|":"|"~"|"."|"("|")"|"{"|"}"|"@"|"+"|"-"|"<"|"/" { 
		if(check_error(1)=="OK"){	
						
						char s=*(yytext);
						return (int)s;
					}
		}
"<-"	{
		if(check_error(1)=="OK"){ return ASSIGN;}
	}	

{TYPEIDN}		{ 
	if(check_error(1)=="OK"){cool_yylval.symbol=idtable.add_string(yytext); 
	return (TYPEID);} }
{OBJIDN}	{
			if(check_error(1)=="OK"){
				cool_yylval.symbol=idtable.add_string(yytext);
				return (OBJECTID);
			}
			
	}

%%

	
